﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Green.AgileMapper.MappingRule;
using Green.FastInvoker;
using Green.Utility;

namespace Green.AgileMapper
{
    public class DefaultObjectMapper : ObjectMapperBase
    {
        private Dictionary<Type, Type> knowTypes;
        public DefaultObjectMapper(IMappingConfigurator mappingConfigurator)
            : base(mappingConfigurator)
        {
            AgileMapperTemplateStrategy = new DefaultAgileMapperTemplateStrategy();
        }

        public override object Warp(Type fromType, object to)
        {
            return this.InnerWarp(fromType, to);
        }

        protected virtual object InnerWarp(Type fromType, object to)
        {
            if (to == null)
                return null;            
            var mappingType = KnowTypeMappingPool.Current.GetSourceType(to.GetType());
            var actualType = mappingType ?? fromType;
            object from = Activator.CreateInstance(actualType);
            var rules = GetMappingOperations(actualType, to.GetType(), from);
            if (rules != null && rules.Length > 0)
            {
                rules.ToList().ForEach(t =>
                {
                    t.WarpFrom(from, to);
                });
            }
            return from;
        }

        public override void Warp(Type toType, object from, object to)
        {
            if (from == null)
            {
                to = null;
                return;
            };

            var targetType = KnowTypeMappingPool.Current.GetTargetType(from.GetType());
            var actualToType = targetType ?? toType;
            var rules = GetMappingOperations(from.GetType(), actualToType, from);
            if (to==null||to.GetType()!=actualToType)
            {
                to = Activator.CreateInstance(actualToType);
            }
            try
            {
                if (rules != null && rules.Length > 0)
                {
                    rules.ToList().ForEach(t =>
                    {
                        t.WarpTo(from, to);
                    });
                }
            }
            catch (Exception)
            {
            }
            
        }

        public override void Warp(object from, object to)
        {
            Warp(to.GetType(), from, to);
        }

        public override void ApplyAgileMapperTemplateStrategy(IAgileMapperTemplateStrategy strategy)
        {
            AgileMapperTemplateStrategy = strategy;
        }

        public override string CodeGenerator(Type FromType, Type toType)
        {
            return CodeGenerator(FromType, toType, Activator.CreateInstance(FromType));
        }

        public override string CodeGenerator(Type FromType, Type toType, object fromObj)
        {
            var rules = GetMappingOperations(FromType, toType, fromObj);

            var code= AgileMapperTemplateStrategy.CodeGenerator(FromType, toType, rules);
            return code;
        }      
    }
}
